package 极客时间.concurrence.并发编程实战篇.Dubbo的管程模型;

import sun.jvm.hotspot.opto.Block;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author idea
 * @Date created in 8:31 上午 2020/7/23
 */
public class BlockQueue<T> {

    private int count, head, tail;

    private Object[] queueArr;

    private final Lock lock = new ReentrantLock();

    private Condition notFull = lock.newCondition();

    private Condition notEmpty = lock.newCondition();

    public BlockQueue() {
        this.queueArr = new Object[10];
    }

    public BlockQueue(int size) {
        this.queueArr = new Object[size];
    }

    public void enq(T val) {
        lock.lock();
        try {
            while (count == getCapacity()) {
                notFull.await();
            }
            queueArr[tail] = val;
            tail++;
            if (tail == getCapacity()) {
                tail = 0;
            }
            count++;
            notEmpty.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 获取队列体积的大小
     *
     * @return
     */
    public int getCapacity() {
        return queueArr.length;
    }

    public T take() {
        lock.lock();
        try {
            while (getCapacity() == 0) {
                notEmpty.await();
            }
            T out = (T) queueArr[head];
            queueArr[head] = null;
            if (head == getCapacity()) {
                head = 0;
            } else {
                head++;
            }
            count--;
            notFull.signalAll();
            return out;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return null;
        } finally {
            lock.unlock();
        }
    }

    public void disPlay(){
        lock.lock();
        try {
            for (Object obj : queueArr) {
                if(obj!=null){
                    System.out.print(obj+" ");
                }
                System.out.print("-");
            }
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        BlockQueue blockQueue = new BlockQueue();
        blockQueue.enq(1);
        blockQueue.enq(2);
        blockQueue.enq(3);
        blockQueue.enq(4);
        blockQueue.disPlay();
        System.out.println();
        blockQueue.take();
        blockQueue.take();
        blockQueue.take();
        blockQueue.take();
        blockQueue.take();
        blockQueue.disPlay();
        Thread.sleep(3000);
        blockQueue.enq(8);
        Thread.sleep(1000);
    }
}
